package com.yunxin.facerecognition.activity;


import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.Drawable;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;


import com.common.network.help.Error;
import com.common.widget.NetworkToast;
import com.yunxin.facerecognition.R;
import com.yunxin.facerecognition.app.MyApp;
import com.yunxin.facerecognition.network.operate.FaceRecognitionFileUploadOperateRequest;
import com.yunxin.facerecognition.network.original.faceRecognition.CheckFaceOriginal;
import com.yunxin.facerecognition.network.request.faceRecognition.UploadFileRequest;
import com.yunxin.facerecognition.network.response.freceRecognition.CheckFaceResponse;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;

public class DetectFaceActivity extends AppCompatActivity implements View.OnClickListener {

    private static String TAG = "DetectFaceActivity";

    private volatile boolean isCameraUpLoad = false;

     private MediaPlayer signFailedMediaPlayer ;
     private MediaPlayer signSufMediaPlayer;

    private CameraManager cManager;


    //为了使照片竖直显示
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();

    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }

    private TextureView cView;//用于相机预览
    /**
     * 头像框
     */
    private RelativeLayout capture_crop_layout;

    private Surface previewSurface;//预览Surface
    private ImageReader cImageReader;
    private Surface captureSurface;//拍照Surface
    HandlerThread cHandlerThread;//相机处理线程
    Handler cHandler;//相机处理
    CameraDevice cDevice;
    CameraCaptureSession cSession;
    CameraDevice.StateCallback cDeviceOpenCallback = null;//相机开启回调
    CaptureRequest.Builder previewRequestBuilder;//预览请求构建
    CaptureRequest previewRequest;//预览请求
    CameraCaptureSession.CaptureCallback previewCallback;//预览回调
    CaptureRequest.Builder captureRequestBuilder;
    CaptureRequest captureRequest;
    CameraCaptureSession.CaptureCallback captureCallback;
    int[] faceDetectModes;
    // Rect rRect;//相机成像矩形
    Size cPixelSize;//相机成像尺寸
    int cOrientation;
    Size captureSize;
    boolean isFront;
    private ImageView scan;
    private Handler mHandler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
        setContentView(R.layout.activity_faceverify);
        signFailedMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.sign_failed);
        signSufMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.sign_suf);
        initVIew();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    /**
     * 初始化界面
     */
    private void initVIew() {
        mHandler = new InnerHandler(this);


        cView = (TextureView) findViewById(R.id.sfv_preview);
        scan = (ImageView) findViewById(R.id.capture_scan_line);
        capture_crop_layout = (RelativeLayout) findViewById(R.id.capture_crop_layout);

        findViewById(R.id.face_photo).setOnClickListener(this);

        ViewGroup.LayoutParams params = capture_crop_layout.getLayoutParams();
        params.width = getResources().getDisplayMetrics().widthPixels / 4 * 3;
        params.height = getResources().getDisplayMetrics().widthPixels / 4 * 3;
        capture_crop_layout.setLayoutParams(params);
    }

    private void startCamera() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                openCamera(true);
            }
        }, 100);
    }

    @SuppressLint("NewApi")
    private void openCamera(boolean isFront) {
        this.isFront = isFront;
        //前置摄像头
        String cId = "";
        if (isFront) {
            cId = CameraCharacteristics.LENS_FACING_BACK + "";
        } else {
            cId = CameraCharacteristics.LENS_FACING_FRONT + "";
        }
        cManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "请授予摄像头权限", Toast.LENGTH_LONG).show();
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 0);
        } else {
            //根据摄像头ID，开启摄像头
            try {
                //获取开启相机的相关参数
                CameraCharacteristics characteristics = cManager.getCameraCharacteristics(cId);
                StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);//获取预览尺寸
                Size[] captureSizes = map.getOutputSizes(ImageFormat.JPEG);//获取拍照尺寸
                cOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//获取相机角度
                Rect cRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);//获取成像区域
                cPixelSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);//获取成像尺寸，同上

                Log.i(TAG, "获取相机角度 : " + cOrientation);

                //可用于判断是否支持人脸检测，以及支持到哪种程度
                faceDetectModes = characteristics.get(CameraCharacteristics
                        .STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);//支持的人脸检测模式
                int maxFaceCount = characteristics.get(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT);
                //支持的最大检测人脸数量

                //此处写死640*480，实际从预览尺寸列表选择
                //previewSizes[2];
                Size sSize = new Size(640, 480);
                //设置预览尺寸（避免控件尺寸与预览画面尺寸不一致时画面变形）
                cView.getSurfaceTexture().setDefaultBufferSize(sSize.getWidth(), sSize.getHeight());

                cManager.openCamera(cId, getCDeviceOpenCallback(), getCHandler());

                TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
                        Animation.RELATIVE_TO_SELF, 0
                        , Animation.RELATIVE_TO_SELF, -1, Animation.RELATIVE_TO_SELF, 0);
                translateAnimation.setDuration(1300);
                translateAnimation.setRepeatCount(-1);
                translateAnimation.setRepeatMode(Animation.RESTART);
                scan.startAnimation(translateAnimation);
            } catch (CameraAccessException e) {
                Log.i(TAG, Log.getStackTraceString(e));
            }
        }
    }


    /**
     * 初始化并获取相机开启回调对象。当准备就绪后，发起预览请求
     */
    @SuppressLint("NewApi")
    private CameraDevice.StateCallback getCDeviceOpenCallback() {
        if (cDeviceOpenCallback == null) {
            cDeviceOpenCallback = new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    cDevice = camera;
                    try {
                        //创建Session，需先完成画面呈现目标（此处为预览和拍照Surface）的初始化
                        camera.createCaptureSession(Arrays.asList(getPreviewSurface(), getCaptureSurface()), new
                                CameraCaptureSession.StateCallback() {
                                    @Override
                                    public void onConfigured(@NonNull CameraCaptureSession session) {
                                        cSession = session;
                                        //构建预览请求，并发起请求
                                        Log.i(TAG, "[发出预览请求]");
                                        try {
                                            session.setRepeatingRequest(getPreviewRequest(), getPreviewCallback(),
                                                    getCHandler());
                                        } catch (CameraAccessException e) {
                                            Log.i(TAG, Log.getStackTraceString(e));
                                        }
                                    }

                                    @Override
                                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                                        session.close();
                                    }
                                }, getCHandler());
                    } catch (CameraAccessException e) {
                        Log.i(TAG, Log.getStackTraceString(e));
                    }
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    camera.close();
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    camera.close();
                }
            };
        }
        return cDeviceOpenCallback;
    }

    /**
     * 初始化并获取相机线程处理
     *
     * @return
     */
    private Handler getCHandler() {
        if (cHandler == null) {
            //单独开一个线程给相机使用
            cHandlerThread = new HandlerThread("cHandlerThread");
            cHandlerThread.start();
            cHandler = new Handler(cHandlerThread.getLooper());
        }
        return cHandler;
    }

    /**
     * 获取支持的最高人脸检测级别
     *
     * @return
     */
    private int getFaceDetectMode() {
        if (faceDetectModes == null) {
            return CaptureRequest.STATISTICS_FACE_DETECT_MODE_FULL;
        } else {
            return faceDetectModes[faceDetectModes.length - 1];
        }
    }

    /**
     * 初始化并获取预览回调对象
     *
     * @return
     */
    @SuppressLint("NewApi")
    private CameraCaptureSession.CaptureCallback getPreviewCallback() {
        if (previewCallback == null) {
            previewCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest
                        request, @NonNull TotalCaptureResult result) {
                    onCameraImagePreviewed(result);
                }
            };
        }
        return previewCallback;
    }

    /**
     * 生成并获取预览请求
     *
     * @return
     */
    @SuppressLint("NewApi")
    private CaptureRequest getPreviewRequest() {
        previewRequest = getPreviewRequestBuilder().build();
        return previewRequest;
    }

    /**
     * 初始化并获取预览请求构建对象，进行通用配置，并每次获取时进行人脸检测级别配置
     *
     * @return
     */
    @SuppressLint("NewApi")
    private CaptureRequest.Builder getPreviewRequestBuilder() {
        if (previewRequestBuilder == null) {
            try {
                previewRequestBuilder = cSession.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                previewRequestBuilder.addTarget(getPreviewSurface());
                previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);//自动曝光、白平衡、对焦
            } catch (CameraAccessException e) {
                Log.i(TAG, Log.getStackTraceString(e));
            }
        }
        previewRequestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, getFaceDetectMode());//设置人脸检测级别
        previewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, 0);
        return previewRequestBuilder;
    }

    /**
     * 获取预览Surface
     *
     * @return
     */
    private Surface getPreviewSurface() {
        if (previewSurface == null) {
            previewSurface = new Surface(cView.getSurfaceTexture());
        }
        return previewSurface;
    }

    /**
     * 处理相机画面处理完成事件，获取检测到的人脸坐标，换算并绘制方框
     *
     * @param result
     */
    @SuppressLint({"NewApi", "LocalSuppress"})
    private void onCameraImagePreviewed(CaptureResult result) {
        Face faces[] = result.get(CaptureResult.STATISTICS_FACES);
        Log.i(TAG, "检测到有人脸，进行拍照操作：faceLength=" + faces.length);
        if (faces.length == 1 && !isCameraUpLoad) {
            //检测到有人脸，控制相机进行拍照操作
            isCameraUpLoad = true;
            executeCapture();
        }
    }

    /**
     * 初始化拍照相关
     */
    @SuppressLint("NewApi")
    private Surface getCaptureSurface() {
        if (cImageReader == null) {
            cImageReader = ImageReader.newInstance(getCaptureSize().getWidth(), getCaptureSize().getHeight(),
                    ImageFormat.JPEG, 2);
            cImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                @Override
                public void onImageAvailable(ImageReader reader) {
                    //拍照最终回调
                    onCaptureFinished(reader);
                }
            }, getCHandler());
            captureSurface = cImageReader.getSurface();
        }
        return captureSurface;
    }

    /**
     * 获取拍照尺寸
     *
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private Size getCaptureSize() {
        if (captureSize != null) {
            return captureSize;
        } else {
            return new Size(cView.getWidth(), cView.getHeight());
        }
    }

    /**
     * 执行拍照
     */
    @SuppressLint("NewApi")
    private void executeCapture() {
        try {
            Log.i(TAG, "发出请求");
            cSession.capture(getCaptureRequest(), getCaptureCallback(), getCHandler());
        } catch (CameraAccessException e) {
            Log.i(TAG, Log.getStackTraceString(e));
            isCameraUpLoad = false;
        }
    }

    @SuppressLint("NewApi")
    private CaptureRequest getCaptureRequest() {
        captureRequest = getCaptureRequestBuilder().build();
        return captureRequest;
    }

    @SuppressLint("NewApi")
    private CaptureRequest.Builder getCaptureRequestBuilder() {
        if (captureRequestBuilder == null) {
            try {
                captureRequestBuilder = cSession.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                //设置拍照回调接口
                captureRequestBuilder.addTarget(getCaptureSurface());
                //TODO 1 照片旋转
                int rotation = getWindowManager().getDefaultDisplay().getRotation();
                int rotationTo = getOrientation(rotation);
                captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, rotationTo);
            } catch (CameraAccessException e) {
                Log.i(TAG, Log.getStackTraceString(e));
                isCameraUpLoad = false;
            }
        }
        return captureRequestBuilder;
    }

    @SuppressLint("NewApi")
    private CameraCaptureSession.CaptureCallback getCaptureCallback() {
        if (captureCallback == null) {
            captureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest
                        request, @NonNull TotalCaptureResult result) {
                }
            };
        }
        return captureCallback;
    }

    /**
     * Retrieves the JPEG orientation from the specified screen rotation.
     *
     * @param rotation The screen rotation.
     * @return The JPEG orientation (one of 0, 90, 270, and 360)
     */
    private int getOrientation(int rotation) {
        return (ORIENTATIONS.get(rotation) + cOrientation + 270) % 360;
    }

    /**
     * 处理相机拍照完成的数据
     *
     * @param reader
     */
    @SuppressLint("NewApi")
    private void onCaptureFinished(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);
        image.close();
        buffer.clear();
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
        showImage(bitmap);
        Runtime.getRuntime().gc();
    }

    /**
     * 保存照片，调用人脸识别接口
     *
     * @param image
     */
    private void showImage(final Bitmap image) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                upload(image);
            }
        });
    }

    private void upload(Bitmap face) {
        if (face == null) {
            Toast.makeText(getApplicationContext(), "拍照出错，请重试！", Toast.LENGTH_SHORT).show();
            isCameraUpLoad = false;
            return;
        }
        try {
            final File file = File.createTempFile(UUID.randomUUID().toString() + "", ".jpg");
            int minWidth = Math.min(face.getWidth(), face.getHeight());
            int x = (face.getWidth() - minWidth) / 2;
            int y = (face.getHeight() - minWidth) / 2;
            Bitmap bitmap = Bitmap.createBitmap(face, x, y, minWidth, minWidth);
            resize(bitmap, file, 480, 480);

          /*  Intent intent = new Intent();
            intent.putExtra("filePath", file.getAbsolutePath());
            setResult(RESULT_OK, intent);
            finish();*/
        } catch (IOException e) {
            isCameraUpLoad = false;
            e.printStackTrace();
        }
    }

    private void deleteFace(File file) {
        if (file != null && file.exists()) {
            file.delete();
        }
    }

    @SuppressLint("NewApi")
    private void closeCamera() {
        if (cSession != null) {
            try {
                cSession.stopRepeating();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
            cSession.close();
            cSession = null;
        }

        if (cDevice != null) {
            cDevice.close();
            cDevice = null;
        }
        if (cImageReader != null) {
            cImageReader.close();
            cImageReader = null;
            captureRequestBuilder = null;
        }
        if (cHandlerThread != null) {
            cHandlerThread.quitSafely();
            try {
                cHandlerThread.join();
                cHandlerThread = null;
                cHandler = null;
            } catch (InterruptedException e) {
                Log.i(TAG, Log.getStackTraceString(e));
            }
        }

        if (captureRequestBuilder != null) {
            captureRequestBuilder.removeTarget(captureSurface);
            captureRequestBuilder = null;
        }
        if (captureSurface != null) {
            captureSurface.release();
            captureSurface = null;
        }
        if (previewRequestBuilder != null) {
            previewRequestBuilder.removeTarget(previewSurface);
            previewRequestBuilder = null;
        }
        if (previewSurface != null) {
            previewSurface.release();
            previewSurface = null;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        startCamera();
    }

    @Override
    protected void onPause() {
        super.onPause();
        closeCamera();
    }

    private static class InnerHandler extends Handler {
        private WeakReference<DetectFaceActivity> mWeakReference;

        public InnerHandler(DetectFaceActivity activity) {
            super();
            this.mWeakReference = new WeakReference<DetectFaceActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mWeakReference == null || mWeakReference.get() == null) {
                return;
            }
            DetectFaceActivity activity = mWeakReference.get();
            if (activity == null) {
                return;
            }
            if (msg == null) {
                return;
            }
            switch (msg.what) {
                default:
                    break;
            }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.face_photo:
                executeCapture();
                break;
            default:
                break;
        }
    }

    private void resize(Bitmap bitmap, File outputFile, int maxWidth, int maxHeight) {
        try {
            int bitmapWidth = bitmap.getWidth();
            int bitmapHeight = bitmap.getHeight();
            // 图片大于最大高宽，按大的值缩放
            if (bitmapWidth > maxHeight || bitmapHeight > maxWidth) {
                float widthScale = maxWidth * 1.0f / bitmapWidth;
                float heightScale = maxHeight * 1.0f / bitmapHeight;

                float scale = Math.min(widthScale, heightScale);
                Matrix matrix = new Matrix();
                matrix.postScale(scale, scale);
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
            }
            FileOutputStream out = new FileOutputStream(outputFile);
            try {
                bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
                uploadFileReq(outputFile);
            } catch (Exception e) {
                isCameraUpLoad = false;
                e.printStackTrace();
            } finally {
                try {
                    out.close();
                } catch (Exception e) {
                    isCameraUpLoad = false;
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            isCameraUpLoad = false;
            e.printStackTrace();
        }
    }

    private void playSignFailed() {
        try {
            signFailedMediaPlayer.prepare();
        } catch (IllegalStateException | IOException e) {

            e.printStackTrace();
        }
        signFailedMediaPlayer.start();

    }

    private void playSignSuf() {
        try {
            signSufMediaPlayer.prepare();
        } catch (IllegalStateException | IOException e) {
             Log.i(TAG,"e = "+e.getMessage());
            e.printStackTrace();
        }
        signSufMediaPlayer.start();

    }

    private void uploadFileReq(File file) {


        UploadFileRequest uploadFileRequest = new UploadFileRequest(new CheckFaceResponse(), new CheckFaceOriginal());

        uploadFileRequest.setHttpUrl(MyApp.Url);

        uploadFileRequest.setFileUrl(MyApp.Url+"Face_checkFace");

        //上传的文件
        Log.i(TAG, "file= " + file.getAbsolutePath());
        if (file.exists()) {

            uploadFileRequest.setFileUpload(file);

            FaceRecognitionFileUploadOperateRequest.instance().faceRecognitionFileUpload(uploadFileRequest, file.getName());
        } else {
            Log.d(TAG, "该文件不存在");
            isCameraUpLoad = false;
        }

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void uploadFileResp(CheckFaceResponse checkFaceResponse) {
        if (!TextUtils.isEmpty(checkFaceResponse.getError())) {
            Log.e(TAG, "1------------ =" + checkFaceResponse.getError());
            if (checkFaceResponse.getError().equals(Error.ERROR_NETWORK_IS_NOT_AVAILABLE)
                    || checkFaceResponse.getError().equals(Error.ERROR_NET_TIMEOUT)) {
                NetworkToast.makeText(getApplicationContext()).show();
            } else {
                //其他错误
                Toast.makeText(this, checkFaceResponse.getError(), Toast.LENGTH_SHORT).show();
            }
            playSignFailed();
        } else {
            CheckFaceOriginal checkFaceOriginal = checkFaceResponse.getData();
            if (checkFaceOriginal != null) {
                Toast.makeText(this, checkFaceResponse.getData().getMsg(), Toast.LENGTH_SHORT).show();
            }
            playSignSuf();
        }
        isCameraUpLoad = false;
    }
}

